package com.algrithom.tree.huffman;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import lombok.Getter;

/**
 * 霍夫曼编码器
 *
 * @author think
 * @version 1.0.0
 */
public class HuffmanEncoder {
    
    private final PriorityQueue queue;
    
    private HuffmanTree tree;
    
    private String[] message;
    
    private final Map<String,Integer> keyMap;
    
    @Getter
    private Map<String,String> codeSet;
    
    public HuffmanEncoder(){
        queue = new PriorityQueue();
        keyMap = new HashMap<>();
    }
    
    /**
     * 获取指定字符串的霍夫曼编码
     *
     * @param msg str
     * @return str
     */
    public String encode(String msg){
        resolveMassage(msg);
        buildCodeSet();
        StringBuilder code = new StringBuilder();
        // 将消息文本的逐个字符翻译成霍夫曼编码
        for (String s : message) {
            code.append(codeSet.get(s));
        }
        return code.toString();
    }
    
    /**
     * 将一段字符串消息解析成单个字符与该字符词频的对应关系，存入Map
     *
     * @param msg str
     */
    private void resolveMassage(String msg){
        // 将消息转换成字符数组
        char[] chars = msg.toCharArray();
        message = new String[chars.length];
        for (int i = 0; i < chars.length; i++) {
            String key = "";
            // 将当前字符转换成字符串
            key = chars[i] + "";
            
            message[i] = key;
            // 如果Map中已存在该字符，则词频加一
            if (keyMap.containsKey(key)) {
                keyMap.put(key,keyMap.get(key) + 1);
            } else {
                // 如果Map中没有该字符，加入Map
                keyMap.put(key,1);
            }
        }
    }
    
    /**
     * 建立对应某段消息的代码集
     */
    private void buildCodeSet(){
        for (Object o : keyMap.entrySet()) {
            Entry entry = (Entry)o;
            // 用该字符和该字符的词频为参数，建立一个新的节点，插入优先级队列
            queue.insert(new HuffmanNode((Integer)entry.getValue(),(String)entry.getKey()));
        }
        queue.display();
        // 利用优先级队列生成霍夫曼树
        tree = queue.buildHuffmanTree();
        // 获取霍夫曼树对应的代码集
        codeSet = tree.getCodeSet();
    }
    
    /**
     * 打印该段消息的代码集
     */
    public void printCodeSet(){
        Iterator<Entry<String,String>> it = codeSet.entrySet().iterator();
        System.out.println("Code set：");
        while (it.hasNext()) {
            Entry<String,String> entry = it.next();
            System.out.println(entry.getKey() + "——>" + entry.getValue());
        }
        System.out.println();
    }
}
